/***
 * * PROJECT
 * *    Logical Neighborhood Routing
 * * VERSION
 * *    $Revision: 1.11 $
 * * DATE
 * *    $Date: 2006/12/14 22:26:36 $
 * * LOG
 * *    $Log: LNRouting.java,v $
 * *    Revision 1.11  2006/12/14 22:26:36  lmottola
 * *    LNScope becomes an interface that includes matches().
 * *
 * *
 * *   Logical Neighborhoods Routing - Java Version
 * *                                
 * *
 * *   This program is free software; you can redistribute it and/or
 * *   modify it under the terms of the GNU General Public License
 * *   as published by the Free Software Foundation; either version 2
 * *   of the License, or (at your option) any later version.
 * *
 * *   This program is distributed in the hope that it will be useful,
 * *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 * *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * *   GNU General Public License for more details.
 * *
 * *   You should have received a copy of the GNU General Public License
 * *   along with this program; if not, you may find a copy at the FSF web
 * *   site at 'www.gnu.org' or 'www.fsf.org', or you may write to the
 * *   Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 * *   Boston, MA  02111-1307, USA
 ***/

package atag.runtime.ln;

import java.util.HashMap;
import java.util.Iterator;
import java.util.Vector;

import atag.runtime.DataItem;
import atag.runtime.NodeInfo;
import atag.runtime.ln.messages.AppMsg;
import atag.runtime.ln.nodeAttributes.NodeAttribute;
import atag.runtime.ln.predicates.LNPredicate;

/**
 * @author Luca Mottola <a
 *         href="mailto:mottola@elet.polimi.it">mottola@elet.polimi.it</a>
 * 
 */
public class LNRouting {

	private NeighborSet neighborSet;

	private HashMap seenMessages;

	private LogicalNeighborhood ln;

	private NodeInfo nodeInfo;

	private byte disseminationParam;

	private long appTime;

	public LNRouting(NodeInfo info, NeighborSet neighborSet,
			byte disseminationParam, LogicalNeighborhood ln) {

		this.disseminationParam = disseminationParam;
		this.ln = ln;
		this.nodeInfo = info;
		this.neighborSet = neighborSet;
		this.seenMessages = new HashMap();
		this.appTime = 0;
	}

	protected void generateAppMsg(DataItem data, LNScope[] scopes) {
		AppMsg msg;

		// TODO: Derive overlapping scopes
		for (int i = 0; i < scopes.length; i++) {
			if (scopes[i].isHopConcerned()) {
				msg = new AppMsg(nodeInfo.getMyId(), appTime++, data,
						scopes[i], scopes[i].getMaxHops());
			} else {
				msg = new AppMsg(nodeInfo.getMyId(), appTime++, data, scopes[i]);
			}
			ln.sendMessage(msg);
		}
	}

	protected void parseAppMsg(AppMsg msg) {

		if (!isAlreadySeen(msg)) {
			if (msg.getLNScope().matches(nodeInfo)) {
				ln.deliver(msg.getData());
			}
			if (!msg.isMaxHops() || msg.getHops() < msg.getMaxHops()) {
				nodeInfo.debugPrint("Forwarding message from "
						+ msg.getSenderId() + " generated from "
						+ msg.getOriginatorId());
				Vector destinations = new Vector(neighborSet
						.returnRandomNeighbors(disseminationParam));
				msg.setDestinations(destinations);
				ln.forwardMessage(msg);
			}
		}
	}

	private boolean isAlreadySeen(AppMsg msg) {

		// TODO: Implement limited buffer
		Vector seenForId = (Vector) seenMessages.get(new Integer(msg
				.getOriginatorId()));

		if (seenForId == null) {
			// Never got a message from this node
			seenForId = new Vector();
			seenForId.add(new Long(msg.getSeqNumber()));
			seenMessages.put(new Integer(msg.getOriginatorId()), seenForId);
			return false;
		} else {
			if (!seenForId.contains(new Long(msg.getSeqNumber()))) {
				seenForId.add(new Long(msg.getSeqNumber()));
				return false;
			} else {
				return true;
			}
		}
	}
}
